package com.chenjl.trace.aspect;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.chenjl.trace.Tracer;
import com.chenjl.trace.enums.AnnotationEnum;
import com.chenjl.trace.enums.SpanTypeEnum;
import com.chenjl.trace.model.Endpoint;
import com.chenjl.trace.model.Span;
import com.mysql.jdbc.PreparedStatement;
import com.mysql.jdbc.Statement;
/**
 * 使用aspect对MySQL操作进行trace埋点
 * 2018-9-10 19:37:37
 * @author chenjinlong
 */
@Aspect
public class MySQLAspect {
	private static final Logger log = LoggerFactory.getLogger(MySQLAspect.class);
	
	@Pointcut("execution(public * com.mysql.jdbc.ConnectionImpl.execSQL(..))")
	public void getPointCut() {
		
	}
	
	@Around(value="getPointCut()")
	public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		Span rootSpan = Tracer.getRootSpan();
		if(rootSpan == null) {
			//无埋点的正常请求
			return proceedingJoinPoint.proceed();
		}
		
		//跳过非业务查询
		Object[] args = proceedingJoinPoint.getArgs();
		Object statementObject = args[0];
		Object sqlObject = args[1];
		if(statementObject == null || args.length != 10) {
			return proceedingJoinPoint.proceed();
		}
		if(sqlObject != null) {
			String sqlObjectStr = String.valueOf(sqlObject);
			if(sqlObjectStr.contains("@@") || sqlObjectStr.contains("SHOW VARIABLES") || sqlObjectStr.contains("SHOW WARNINGS") || sqlObjectStr.contains("USER()")) {
				return proceedingJoinPoint.proceed();
			}	
		}
		
		String sql = null;
		if(statementObject instanceof PreparedStatement) {
			sql = String.valueOf(statementObject);
			sql = sql.substring(sql.indexOf(":") +1).replaceAll("\n","");
		}
		else if (statementObject instanceof Statement) {
			sql = String.valueOf(sqlObject).replaceAll("\n","");
		}
		
		Object result = null;
		Throwable throwable = null;
		
		Connection connection = (Connection) proceedingJoinPoint.getTarget();
		DatabaseMetaData databaseMetaData = connection.getMetaData();
		String jdbcUrl = databaseMetaData.getURL();
		
		Endpoint endpoint = new Endpoint();
		endpoint.setServiceName("mysql access");
		endpoint.setHost(jdbcUrl);
		String spanId = Tracer.begin(rootSpan.getTraceId(),rootSpan.getId(),sql,endpoint,AnnotationEnum.CLIENT_SEND,SpanTypeEnum.MYSQL_ACCESS);
		
		boolean hasExceptionFlag = false;
		log.info(" -->--MySQL access begin, url : {} ,sql : {}",jdbcUrl,sql);
		try {
			result = proceedingJoinPoint.proceed();
		}
		catch (Throwable e) {
			hasExceptionFlag = true;
			throwable = e;
		}
		
		Map<String,String> datas = new HashMap<String,String>(2);
		datas.put("hasException",String.valueOf(hasExceptionFlag));
		Tracer.end(spanId,endpoint,AnnotationEnum.CLIENT_RECEIVE,datas);
		log.info(" -->--MySQL access end, url : {} ,sql : {}，error: {}",jdbcUrl,sql,throwable!=null);
		
		if(throwable != null) {
			throw throwable;
		}
		return result;
	}
}